/**
 * 中文存储封装 (zh-storage.js)
 * 支持本地存储操作、链式调用、自动JSON序列化/反序列化
 * 中文方法命名 + JSDoc 参数提示
 */

class 存储 {
  /**
   * 构造函数 - 创建存储操作实例
   * @param {Storage} [存储对象=localStorage] 存储对象，可以是localStorage或sessionStorage
   */
  constructor(存储对象 = localStorage) {
    this._存储 = 存储对象;
  }

  /**
   * 获取原始存储对象
   * @returns {Storage} 原始的localStorage或sessionStorage对象
   */
  取值() {
    return this._存储;
  }

  /**
   * 存储数据到存储对象
   * @param {string} 键 存储键名
   * @param {*} 值 要存储的数据
   * @param {number} [过期时间毫秒] 可选的过期时间（毫秒）
   * @returns {存储} 返回this以支持链式调用
   */
  存储(键, 值, 过期时间毫秒) {
    const 存储数据 = {
      值,
      过期时间: 过期时间毫秒 ? Date.now() + 过期时间毫秒 : null
    };
    this._存储.setItem(键, JSON.stringify(存储数据));
    return this;
  }

  /**
   * 从存储对象读取数据
   * @param {string} 键 存储键名
   * @returns {*} 存储的值，如果不存在或已过期则返回null
   */
  读取(键) {
    const 存储数据 = this._存储.getItem(键);
    if (!存储数据) return null;
    
    try {
      const { 值, 过期时间 } = JSON.parse(存储数据);
      
      // 检查是否过期
      if (过期时间 && Date.now() > 过期时间) {
        this._存储.removeItem(键);
        return null;
      }
      
      return 值;
    } catch (e) {
      // 兼容旧格式（直接存储的值）
      try {
        return JSON.parse(存储数据);
      } catch {
        return 存储数据;
      }
    }
  }

  /**
   * 删除存储对象中的数据
   * @param {string} 键 存储键名
   * @returns {存储} 返回this以支持链式调用
   */
  删除(键) {
    this._存储.removeItem(键);
    return this;
  }

  /**
   * 清空存储对象中的所有数据
   * @returns {存储} 返回this以支持链式调用
   */
  清空() {
    this._存储.clear();
    return this;
  }

  /**
   * 检查存储对象中是否存在指定键
   * @param {string} 键 存储键名
   * @returns {boolean} 是否存在该键
   */
  包含(键) {
    return this._存储.hasOwnProperty(键);
  }

  /**
   * 获取存储对象中的所有键名
   * @returns {Array<string>} 键名数组
   */
  取键() {
    const 键列表 = [];
    for (let i = 0; i < this._存储.length; i++) {
      键列表.push(this._存储.key(i));
    }
    return 键列表;
  }

  /**
   * 获取存储对象中的所有值
   * @returns {Array<any>} 值数组
   */
  取值列表() {
    const 值列表 = [];
    for (let i = 0; i < this._存储.length; i++) {
      const 键 = this._存储.key(i);
      值列表.push(this.读取(键));
    }
    return 值列表;
  }

  /**
   * 获取存储对象中的所有键值对
   * @returns {Array<Array<string, any>>} 键值对数组
   */
  取条目() {
    const 条目列表 = [];
    for (let i = 0; i < this._存储.length; i++) {
      const 键 = this._存储.key(i);
      条目列表.push([键, this.读取(键)]);
    }
    return 条目列表;
  }

  /**
   * 获取存储对象中的项目数量
   * @returns {number} 项目数量
   */
  大小() {
    return this._存储.length;
  }

  /**
   * 批量存储多个数据项
   * @param {Object} 数据对象 键值对对象
   * @param {number} [过期时间毫秒] 可选的过期时间（毫秒）
   * @returns {存储} 返回this以支持链式调用
   */
  批量存储(数据对象, 过期时间毫秒) {
    for (const [键, 值] of Object.entries(数据对象)) {
      this.存储(键, 值, 过期时间毫秒);
    }
    return this;
  }

  /**
   * 批量读取多个数据项
   * @param {...string} 键列表 要读取的键名列表
   * @returns {Object} 键值对对象
   */
  批量读取(...键列表) {
    const 结果 = {};
    for (const 键 of 键列表) {
      结果[键] = this.读取(键);
    }
    return 结果;
  }

  /**
   * 批量删除多个数据项
   * @param {...string} 键列表 要删除的键名列表
   * @returns {存储} 返回this以支持链式调用
   */
  批量删除(...键列表) {
    for (const 键 of 键列表) {
      this._存储.removeItem(键);
    }
    return this;
  }

  /**
   * 获取存储对象的近似使用量（字节数）
   * @returns {number} 存储使用量（字节）
   */
  存储使用量() {
    let 总大小 = 0;
    for (let i = 0; i < this._存储.length; i++) {
      const 键 = this._存储.key(i);
      const 值 = this._存储.getItem(键);
      总大小 += 键.length + 值.length;
    }
    return 总大小;
  }

  /**
   * 清空所有过期的数据项
   * @returns {存储} 返回this以支持链式调用
   */
  清空过期数据() {
    for (let i = 0; i < this._存储.length; i++) {
      const 键 = this._存储.key(i);
      this.读取(键); // 读取会自动清理过期数据
    }
    return this;
  }

  /** 静态方法 */

  /**
   * 静态方法：创建本地存储实例
   * @static
   * @returns {存储} 基于localStorage的存储实例
   */
  static 本地() {
    return new 存储(localStorage);
  }

  /**
   * 静态方法：创建会话存储实例
   * @static
   * @returns {存储} 基于sessionStorage的存储实例
   */
  static 会话() {
    return new 存储(sessionStorage);
  }

  /**
   * 静态方法：检查存储对象是否可用
   * @static
   * @param {Storage} [存储对象=localStorage] 要检查的存储对象
   * @returns {boolean} 存储对象是否可用
   */
  static 是否可用(存储对象 = localStorage) {
    try {
      const 测试键 = '__storage_test__';
      存储对象.setItem(测试键, '1');
      存储对象.removeItem(测试键);
      return true;
    } catch {
      return false;
    }
  }
}

// 规范导出
export { 存储 };
export default 存储;